package com.sunmouse.toolkit.service;

import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.IBinder;
import android.support.v7.app.NotificationCompat;

import com.sunmouse.toollib.receiver.OnReceiveListener;
import com.sunmouse.toollib.utils.LogUtils;
import com.sunmouse.toollib.utils.PersistentUtils;
import com.sunmouse.toollib.utils.StringUtils;
import com.sunmouse.toollib.utils.ToastUtils;
import com.sunmouse.toollib.utils.system.NetUtils;
import com.sunmouse.toolkit.R;
import com.sunmouse.toolkit.activity.ContentActivity;
import com.sunmouse.toolkit.receiver.CommandReceiver;
import com.sunmouse.toolkit.constant.Config;
import com.sunmouse.toolkit.constant.Value;
import com.sunmouse.toolkit.util.ChatUtil;
import com.sunmouse.toolkit.util.PageUtil;

import java.net.ConnectException;
import java.util.ArrayList;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

public class ExceptionService extends Service implements ChatUtil.OnMessageListener, OnReceiveListener {

    public static final int RECONNECT_TIME = 5 * 1000;
    private ChatUtil mUtils;
    private CommandReceiver mReceiver;
    private Timer mTimer;
    private ArrayList<String> exceptions;
    private int count;
    private PersistentUtils mPersistentUtils;
    private NotificationManager mManager;
    private boolean isTaskLaunched;
    private Intent mIntent;
    private boolean notifyFlag;


    public ExceptionService() {

    }


    @Override
    public void onCreate() {
        super.onCreate();
        mUtils = ChatUtil.getInstance(ChatUtil.generateName());
        mUtils.setOnMessageListener(this);
        mUtils.launchClient(ChatUtil.SERVER, ChatUtil.PORT);
        mTimer = new Timer();

        exceptions = new ArrayList<>();
        mPersistentUtils = PersistentUtils.getInstance(this, "tool_kit");
        mPersistentUtils.writeInt(Config.Key.STATUS, Value.CONNECTED);
        mManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

        mReceiver = new CommandReceiver();
        registerReceiver(mReceiver, new IntentFilter(Value.Action.EXCEPTION));
        mReceiver.setOnReceiveListener(this);

        notifyFlag = true;
    }

    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        throw new UnsupportedOperationException("Not yet implemented");
    }

    @Override
    public void onMessage(String msg) {
        count++;
        exceptions.add(msg);
        mPersistentUtils.writeList(Config.Key.EXCEPTION, exceptions);

        mIntent = new Intent(Value.Action.EXCEPTION_RECEIVER);
        mIntent.putExtra(Config.Key.EXCEPTION, msg);
        sendBroadcast(mIntent);

        if (notifyFlag) {
            mIntent = new Intent(getService(), ContentActivity.class);
            mIntent.putExtra(Config.Key.INDEX, PageUtil.Index.SOCKET);
            PendingIntent mPending = PendingIntent.getActivity(getService(), 5, mIntent, PendingIntent.FLAG_ONE_SHOT);
            NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(getService());
            mBuilder.setSmallIcon(R.mipmap.app_logo)
                    .setContentTitle("Reesola")
                    .setAutoCancel(true)   //cancel if user click it
                    .setContentText("[" + count + "]" + "条异常")
                    .setContentIntent(mPending)
            ;
            mManager.notify(1, mBuilder.build());
        }
    }

    @Override
    public void onError(Exception e) {
        //handle error here
        if (!NetUtils.isNetConnected(this)){
            ToastUtils.simpleToast(this,"网络未连接,请连网后再试");
            return;
        }
        LogUtils.v("-----------" + e.toString());
        LogUtils.v("-----------" + e.getLocalizedMessage());
        if (e instanceof ConnectException) {
            /**
             * connect failed then reconnect
             */
            startReconnect();
        } else if (!mUtils.isServerValid(e)) {
            startReconnect();
        }
    }

    /**
     * reconnect remote server
     */
    private void startReconnect() {
        if (!isTaskLaunched) {
            mTimer.schedule(new ReconnectTask(), 0, RECONNECT_TIME);
            isTaskLaunched = true;
        }
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        unregisterReceiver(mReceiver);
        mUtils.disconnect();
        if (mTimer != null) {
            mTimer.cancel();
            mTimer.purge();
            mTimer = null;
        }
    }

    @Override
    public void onReceive(Context context, Intent intent) {
        int control = intent.getIntExtra(Config.Key.CONTROL, -1);
        switch (control) {
            case Value.Control.CONNECT:
                mUtils.connect();
                break;
            case Value.Control.DISCONNECT:
                mUtils.disconnect();
                break;
            case Value.Control.OPEN_NOTIFICATION:
                notifyFlag = true;
                mPersistentUtils.writeInt(Config.Key.NOTIFICATION_STATUS,Value.Control.OPEN_NOTIFICATION );
                break;
            case Value.Control.CLOSE_NOTIFICATION:
                notifyFlag = false;
                mPersistentUtils.writeInt(Config.Key.NOTIFICATION_STATUS, Value.Control.CLOSE_NOTIFICATION);
                break;
            case Value.Control.STOP:
                stopSelf();
                break;
        }
    }


    public Context getService() {
        return this;
    }

    /**
     * reconnect task
     */
    private class ReconnectTask extends TimerTask {
        boolean flag;

        public ReconnectTask() {
            flag = true;
        }

        @Override
        public void run() {
            if (flag) {
                mUtils.connect();
                if (mUtils.isConnected()) {
//                    flag = false;
                    isTaskLaunched = false;
                    this.cancel();
                }
                LogUtils.v("------try to reconnect..." + StringUtils.SDF.format(new Date()));
            }
        }
    }
}
